package com.gitee.faster.webdav.kernel.protocol;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ServiceLoaderUtil;
import com.gitee.faster.webdav.common.constant.MethodEnum;
import com.gitee.faster.webdav.exception.WebDavException;
import com.gitee.faster.webdav.kernel.protocol.dispatcher.MethodDispatcher;
import com.gitee.faster.webdav.kernel.protocol.filter.HttpFilter;
import com.gitee.faster.webdav.kernel.protocol.handler.ExceptionHandler;
import com.gitee.faster.webdav.kernel.protocol.handler.ExceptionHandlerDefault;
import lombok.extern.slf4j.Slf4j;
import org.smartboot.http.server.HttpRequest;
import org.smartboot.http.server.HttpResponse;
import org.smartboot.http.server.HttpServerHandler;

import java.util.*;

/**
 * 接收所有请求，并根据不同的请求方法，移交至对应的处理器执行
 *
 * @author hongda.li
 */
@Slf4j
public class HttpDispatcherHandler extends HttpServerHandler {

    private final List<HttpFilter> filterList;

    private final ExceptionHandler exceptionHandler;

    private final Map<MethodEnum, MethodDispatcher> dispatcherMapping = new EnumMap<>(MethodEnum.class);

    public HttpDispatcherHandler() {
        // 过滤器
        this.filterList = ServiceLoaderUtil.loadList(HttpFilter.class);
        this.filterList.sort(Comparator.comparingInt(HttpFilter::order));

        // 异常处理器
        this.exceptionHandler = ObjectUtil.defaultIfNull(ServiceLoaderUtil.loadFirst(ExceptionHandler.class), new ExceptionHandlerDefault());

        // 转发器
        List<MethodDispatcher> dispatcherList = ServiceLoaderUtil.loadList(MethodDispatcher.class);
        dispatcherList.forEach(handler -> this.dispatcherMapping.put(handler.supported(), handler));
    }

    @Override
    public void handle(HttpRequest request, HttpResponse response) {
        // 将请求与响应封装为访问器，提供快速访问请求、响应等方法
        HttpExchange accessor = new HttpExchange(request, response);

        try {
            // 转发请求
            this.dispatch(accessor);
        } catch (Exception exception) {
            // 处理异常
            this.exceptionHandler.onError(accessor, WebDavException.from(exception));
        }
    }

    /**
     * 内部处理逻辑
     *
     * @param accessor 访问器
     */
    private void dispatch(HttpExchange accessor) {
        // 先按顺序执行过滤器
        for (HttpFilter filter : this.filterList) {
            boolean doNext = filter.doNext(accessor);
            if (!doNext) {
                return;
            }
        }

        // 方法枚举
        MethodEnum methodEnum = accessor.getMethodEnum();

        // 获取当前方法对应的处理器
        MethodDispatcher dispatcher = this.dispatcherMapping.get(methodEnum);
        Objects.requireNonNull(dispatcher);

        // 处理具体方法
        dispatcher.dispatch(accessor);
    }
}
